#include "precompiled.h"
#include "enhancement.h"
using namespace std;
using namespace weo::engine::item;
using namespace weo::engine::character::shaman;

Enhancement::Enhancement()
{
    Meleedps::Init();
    m_Classnr = weo::engine::character::Character::isAllowed("Shaman");
    m_Basevalues.push_back(Attribute("Agility",59));
    m_Basevalues.push_back(Attribute("Intellect",103));
    m_Basevalues.push_back(Attribute("Strength",103));
    m_Basevalues.push_back(Attribute("Stamina",116));
    m_Basevalues.push_back(Attribute("Spirit",122));
    m_Basevalues.push_back(Attribute("CritSpellRating",2.2f*CritSpellRating));
    m_Basevalues.push_back(Attribute("CritRating",1.66f*CritRating)); // crit
    m_Basevalues.push_back(Attribute("AttackPower",120)); // ap
    m_Basevalues.push_back(Attribute("Health",2979)); // health
    m_Basevalues.push_back(Attribute("Mana",2678)); // mana
    m_Basevalues.push_back(Attribute("HitRating",9*HitRating)); // hr
    m_Basevalues.push_back(Attribute("CritRating",5*CritRating)); // cr
    m_Equip.Mode(0);
    BOOST_FOREACH(Attribute attr, m_Basevalues)
    {
        handleAttribute(attr);
    }
    // base settings finished
}
float Enhancement::evaluateTF()
{
    float wdps1 = m_Equip[46];
    float wdps2 = m_Equip[48];
    float ws1 = m_Equip[47];
    float ws2 = m_Equip[49];
    float baseap = m_Equip[30];
    float crit = m_Equip[6]/CritRating;
    float hit = m_Equip[7]/HitRating;
    float haste = m_Equip[10]/HasteRating;
    // -- glancing blow calculation -- //
    float glancingreduction = 25;
    float glancingprob = 25;
    float glancing = glancingreduction * glancingprob / 100;
    // -- some init values -- //
    float dodge = 6.5f - (m_Equip[51]/ExpertiseRating) * 0.25f;
    float hitwhite = min<float>(100 - 9 - 19 + hit, 100);
    float hityellow = min<float>(100 - 9 + hit, 100);
    float avghit = (hityellow + hitwhite) / 200;
    float noncrit = (1 - crit / 100 );
    float minwftime = 3.0f;
    float flurryvalue = 0.30f;
    float asmh = ws1 / ((1 + flurryvalue) * (1 + haste / 100)); // fully flurried attack speed
    float asoh = ws2 / ((1 + flurryvalue) * (1 + haste / 100)); // fully flurried attack speed
    float mhswingsin3 = floor(minwftime/asmh);
    float ohswingsin3 = floor(minwftime/asoh);
    float wfprocprobmh = 0.2f/mhswingsin3;
    float wfprocproboh = 0.2f/ohswingsin3;
    float wfprocprob = wfprocprobmh+wfprocproboh-wfprocprobmh*wfprocproboh;
    // -- some init values -- //
    float attackspeed = (asmh+asoh)/2;
    float ssinthree = 3 * attackspeed / 5; // how many stormstrikes in 3 swings
    float wftime = 1 / (1 + 1.5f * (wfprocprob / attackspeed)); // actually the probability that we can proc wf while being flurried
    float flurryprob = min<float>(1 - pow(noncrit, 3 + 1 - pow(1 - wfprocprob, wftime * 3) + ssinthree), 1.0); // flurry calc
    float wsmh = (ws1 / (1 + haste / 100)) * (1 - flurryprob) + (ws1 / ((1 + haste / 100) * (1 + flurryvalue))) * flurryprob; // actual mh ws (flurried/hasted)
    float wsoh = (ws2 / (1 + haste / 100)) * (1 - flurryprob) + (ws2 / ((1 + haste / 100) * (1 + flurryvalue))) * flurryprob; // actual oh ws (flurried/hasted)
    float avgspeed = (wsmh + wsoh) / 2;
    float exwftime = max<float>(avgspeed / wfprocprob, minwftime); // expected wf time
    float wfproc = avgspeed / exwftime; // wf proc prob  (should be 36% after all, only different for daggers)
    float wfprocmh = ws2 / (ws1 + ws2) * wfproc; // mh wf proc prob
    float wfprocoh = ws1 / (ws1 + ws2) * wfproc; // oh wf proc prob
    float ssmh = 1 + (hityellow / (hitwhite - glancing)) * (wsmh / 10); // corrected stormstrike haste factor mh
    float ssoh = 1 + (hityellow / (hitwhite - glancing)) * (wsoh / 10); // corrected stormstrike haste factor oh
    float hastemh = ws1 / wsmh; // the actual haste factor
    float hasteoh = ws2 / wsoh; // the actual haste factor
    // -- ap calculation below, first we calc the hit count in 10s for UR, then use this to calculate UR uptime) -- //
    float hitsin10 = 0.01f * ((hitwhite - glancingprob - dodge) * (2 * 10 / avgspeed)) * (1 + (wfproc * (hityellow - dodge) * 0.01f));
    if(m_Equip.hasSpecial(413510))
    {
        baseap += 137.5f;
    }
    if(m_Equip.hasSpecial(636071))
    {
        baseap += 70;
    }
    float ap = baseap * (1 + 0.1f * (1 - pow(noncrit, hitsin10)));
    float wfap = 475;
    if(m_Equip.hasSpecial(1134694))
    {
        wfap += 80;
    }
    if(m_Equip.hasSpecial(445202))
    {
        crit *=1.03f;
    }
    // -- actual dps calculation below -- //
    float mhwhitedps = 0.01f * (hitwhite + crit - glancing - dodge) * (wdps1 + ap / 14);
    float mhyellowdps = 0.01f * 0.01f * (hitwhite - dodge) * (hityellow + crit - dodge) * 2 * wfprocmh * 1.4f * (wdps1 + (wfap+ap) / 14);
    float ssmhdps = (ssmh - 1 ) * mhwhitedps;
    float ohwhitedps = 0.5f * 0.01f * (hitwhite + crit - glancing - dodge) * (wdps2 + ap / 14);
    float ohyellowdps = 0.5f * 0.01f * 0.01f * (hitwhite - dodge) * (hityellow + crit - dodge) * 2 * wfprocoh * 1.4f * (wdps2 + (2 * wfap + ap) / 14);
    float ssohdps = (ssoh - 1 ) * ohwhitedps;
    float whitedps = 1.1f * (hastemh * mhwhitedps + hasteoh * ohwhitedps);
    float yellowdps = 1.1f * (hastemh * mhyellowdps + hasteoh * ohyellowdps);
    float ssdps = 1.1f * (ssmhdps + ssohdps);
    float dps = whitedps + yellowdps + ssdps;
    float armorreduction = max<float>((MobArmor - m_Equip[50])/(MobArmor - m_Equip[50] + 10557.5f),0);
    return (1.0f-armorreduction) * m_CondFactor * dps;
}
/*
float Enhancement::evaluateTF()
{
float wdps1 = m_Equip[46];
float wdps2 = m_Equip[48];
float ws1 = m_Equip[47];
float ws2 = m_Equip[49];
float baseap = m_Equip[30];
float crit = m_Equip[6]/CritRating;
float hit = m_Equip[7]/HitRating;
float haste = m_Equip[10]/HasteRating;
// -- glancing blow calculation -- //
float glancingreduction = 25;
float glancingprob = 25;
float glancing = glancingreduction * glancingprob / 100;
// -- some init values -- //
float dodge = 5.0f;
float hitwhite = min<float>(100 - 5 - 19 + hit, 100);
float hityellow = min<float>(100 - 5 + hit, 100);
float avghit = (hityellow + hitwhite) / 200;
float noncrit = (1 - crit / 100 );
float minwftime = 3.0f;
float flurryvalue = 0.30f;
float asmh = ws1 / ((1 + flurryvalue) * (1 + haste / 100)); // fully flurried attack speed
float asoh = ws2 / ((1 + flurryvalue) * (1 + haste / 100)); // fully flurried attack speed
// -- some init values -- //
float attackspeed = (asmh+asoh)/2;
float ssinthree = 3 * attackspeed / 5; // how many stormstrikes in 3 swings
float flurryprob = min<float>(1 - pow(noncrit, 3 + ssinthree), 1.0); // flurry calc
float wsmh = (ws1 / (1 + haste / 100)) * (1 - flurryprob) + (ws1 / ((1 + haste / 100) * (1 + flurryvalue))) * flurryprob; // actual mh ws (flurried/hasted)
float wsoh = (ws2 / (1 + haste / 100)) * (1 - flurryprob) + (ws2 / ((1 + haste / 100) * (1 + flurryvalue))) * flurryprob; // actual oh ws (flurried/hasted)
float avgspeed = (wsmh + wsoh) / 2;
float ssmh = 1 + (hityellow / (hitwhite - glancing)) * (wsmh / 10); // corrected stormstrike haste factor mh
float ssoh = 1 + (hityellow / (hitwhite - glancing)) * (wsoh / 10); // corrected stormstrike haste factor oh
float hastemh = ws1 / wsmh; // the actual haste factor
float hasteoh = ws2 / wsoh; // the actual haste factor
// -- ap calculation below, first we calc the hit count in 10s for UR, then use this to calculate UR uptime) -- //
float hitsin10 = 0.01f * ((hitwhite - glancingprob - dodge) * (2 * 10 / avgspeed));
if(m_Equip.hasSpecial(413510))
{
baseap += 206.25f;
}
float ap = baseap * (1 + 0.1f * (1 - pow(noncrit, hitsin10)));
// -- actual dps calculation below -- //
float mhwhitedps = 0.01f * (hitwhite + crit - glancing - dodge) * (wdps1 + ap / 14);
float mhyellowdps = 0.01f * (hitwhite - dodge) * 0.86f  * 1.15f * 1.05f * 1.33f * (35 * ws1 + ap * 0.03f)/ws1;
float ssmhdps = (ssmh - 1 ) * mhwhitedps;
float ohwhitedps = 0.5f * 0.01f * (hitwhite + crit - glancing - dodge) * (wdps2 + ap / 14);
float ohyellowdps = 0.01f * (hitwhite - dodge) * 0.86f  * 1.15f * 1.05f * 1.33f * (35 * ws2 + ap * 0.03f)/ws2;
float ssohdps = (ssoh - 1 ) * ohwhitedps;
float whitedps = 1.1f * (hastemh * mhwhitedps + hasteoh * ohwhitedps);
float yellowdps = 1.1f * (hastemh * mhyellowdps + hasteoh * ohyellowdps);
float ssdps = 1.1f * (ssmhdps + ssohdps);
float dps = whitedps + yellowdps + ssdps;
float armorreduction = max<float>((MobArmor - m_Equip[50])/(MobArmor - m_Equip[50] + 10557.5f),0);
return (1-armorreduction) * (whitedps + ssdps) + yellowdps;
}
*/
void Enhancement::filterEquip(std::vector<std::vector<const weo::engine::item::Item*>>& items)
{
    for(unsigned int i = 0;i<10;i++)
    {
        int subtype = 3;
        if(i == 1 || i == 3)
        {
            vector<const Item*> temp = m_Database->getPtrbyType(1,i+1);
            items.push_back(temp);
        }
        else
        {
            vector<const Item*> temp = m_Database->getPtrbyType(1,i+1,3); // mail		
            vector<const Item*> temp2 = m_Database->getPtrbyType(1,i+1,2); // leather
            vector<const Item*>::iterator it;
            for(it=temp2.begin();it!=temp2.end();it++)
            {
                temp.push_back(*it);
            }
            items.push_back(temp);
        }
    }
    items.push_back(m_Database->getPtrbyType(2,0));
    items.push_back(m_Database->getPtrbyType(2,0));
    items.push_back(m_Database->getPtrbyType(3,0));
    items.push_back(m_Database->getPtrbyType(3,0));
    // main hand weapons
    vector<const Item*> mainhand;
    for(int i = 2;i<6;i++)
    {
        for(int j = 1;j<3;j++)
        {
            vector<const Item*> weapon = m_Database->getPtrbyType(4,j,i);
            vector<const Item*>::iterator it;
            for(it=weapon.begin();it!=weapon.end();it++)
            {
                mainhand.push_back(*it);
            }
        }
    }
    // off hand weapons
    vector<const Item*> offhand;
    for(int i = 2;i<6;i++)
    {
        for(int j = 1;j<4;j+=2)
        {
            vector<const Item*> weapon = m_Database->getPtrbyType(4,j,i);
            vector<const Item*>::iterator it;
            for(it=weapon.begin();it!=weapon.end();it++)
            {
                offhand.push_back(*it);
            }
        }
    }
    items.push_back(mainhand);
    items.push_back(offhand);
    items.push_back(m_Database->getPtrbyType(4,5,15)); // totems
    items.push_back(m_Database->getPtrbyType(5,0));
    Meleedps::filterEquip(items);
}
void Enhancement::handleAttribute(const Attribute& attr)
{
    switch(attr.Type())
    {
    default:
        Meleedps::handleAttribute(attr);
        break;
    }
}
